package eDpLib.events
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.MouseEvent;
	
	public class EventDispatcherProxy implements IEventDispatcher
	{
		public var proxyTarget:IEventDispatcher; //the item that we are intercepting and redispatching, this being the target, should be set in subclasses
		public var proxy:IEventDispatcher; //generally this, but you could assing another IEventDispatcher to be the stand end target
		
		////////////////////////////////////////////////////////////////////////
		//	CONSTRUCTOR
		////////////////////////////////////////////////////////////////////////
		
		public function EventDispatcherProxy ()
		{
			proxy = this;
		}
		
		////////////////////////////////////////////////////////////////////////
		//	LISTENER HASH
		////////////////////////////////////////////////////////////////////////
		
		protected var listenerHash:Object = {}; //will contain a value i.e. listenerHash.eventType = {listener:eventListenerFunction};
		
		protected function setListenerHashProperty (type:String, listener:Function):void
		{
			if (!listenerHash.hasOwnProperty(type))
				listenerHash[type] = {listener:listener};
		}
		
		protected function hasListenerHashProperty (type:String):Boolean
		{
			return listenerHash.hasOwnProperty(type);			
		}
		
		protected function getListenerHashProperty (type:String):Function
		{
			var func:Function;
			
			if (listenerHash.hasOwnProperty(type))
				func = listenerHash[type].listener as Function;
				
			return func;
		}
		
		protected function removeListenerHashProperty (type:String):Boolean
		{
			if (listenerHash.hasOwnProperty(type))
			{
				listenerHash[type] = null;
				delete listenerHash[type];
				
				return true;
			}
			
			return false;
		}
		
		////////////////////////////////////////////////////////////////////////
		//	MISC. PROXY METHODS
		////////////////////////////////////////////////////////////////////////
		
		private var _interceptedEventTypes:Array = generateEventTypes();
		
		protected function generateEventTypes ():Array
		{
			var evtTypes:Array = [];
			evtTypes.push(
				MouseEvent.CLICK,
				MouseEvent.DOUBLE_CLICK, 
				MouseEvent.MOUSE_DOWN, 
				MouseEvent.MOUSE_MOVE, 
				MouseEvent.MOUSE_OUT,
				MouseEvent.MOUSE_OVER,
				MouseEvent.MOUSE_UP,
				MouseEvent.MOUSE_WHEEL,
				MouseEvent.ROLL_OUT,
				MouseEvent.ROLL_OVER
				);
				
			return evtTypes;
		}
		
		protected function checkForProxy (type:String):Boolean
		{
			var evtType:String;
			for each (evtType in _interceptedEventTypes)
			{
				if (type == evtType)
					return true;
			}
			
			return false;
		}
		
		protected function eventDelegateFunction (evt:Event):void
		{
			evt.stopImmediatePropagation(); //prevent from further bubbling up thru display list
			var pEvt:ProxyEvent = new ProxyEvent(proxy, evt);
			
			var func:Function;
			if (hasListenerHashProperty(evt.type))
			{
				func = getListenerHashProperty(evt.type);
				func.call(this, pEvt);
			}
		}
		
		////////////////////////////////////////////////////////////////////////
		//	EVENT DISPATCHER HOOKS
		////////////////////////////////////////////////////////////////////////
		
		protected var eventDispatcher:EventDispatcher = new EventDispatcher(IEventDispatcher(this));
		
		public function hasEventListener (type:String):Boolean
		{
			if (checkForProxy(type))
				return proxyTarget.hasEventListener(type);
			
			else
				return eventDispatcher.hasEventListener(type);
		}
		
		public function willTrigger (type:String):Boolean
		{
			if (checkForProxy(type))
				return proxyTarget.willTrigger(type);
			
			else
				return eventDispatcher.willTrigger(type);
		}
		
		public function addEventListener (type:String, listener:Function, useCapture:Boolean = false, priority:int = 0.0, useWeakReference:Boolean = false):void
		{
			if (checkForProxy(type))
			{
				//need to register real function with event
				if (!hasListenerHashProperty(type))
				{
					setListenerHashProperty(type, listener);
					proxyTarget.addEventListener(type ,eventDelegateFunction, useCapture, priority, useWeakReference);
				}
			}
			
			else
				eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		public function removeEventListener (type:String, listener:Function, useCapture:Boolean = false):void
		{
			if (checkForProxy(type))
			{
				if (hasListenerHashProperty(type))
				{
					removeListenerHashProperty(type);
					proxyTarget.removeEventListener(type ,eventDelegateFunction, useCapture);
				}
			}
			
			else
				eventDispatcher.addEventListener(type, listener, useCapture);
		}
		
		public function dispatchEvent (event:Event):Boolean
		{
			return eventDispatcher.dispatchEvent(event);
		}
		
	}
}